import { HttpStatus, Logger, UnprocessableEntityException, ValidationPipe } from '@nestjs/common';
import { ValidationError } from 'class-validator';
import { NestFactory, Reflector } from '@nestjs/core';
import { app as electronApp } from 'electron';
import type { MicroserviceOptions } from '@nestjs/microservices';
import { ElectronIpcTransport } from '@doubleshot/nest-electron';
import { IpcModule } from './ipc/ipc.module';
import { FastifyAdapter, NestFastifyApplication } from '@nestjs/platform-fastify';
import { AppModule } from './service/app.module';
import { join } from 'path';
import { LoggerService } from './shared/logger/logger.service';
import { ApiExceptionFilter } from './common/filters/api-exception.filter';
import { ApiTransformInterceptor } from './common/interceptors/api-transform.interceptor';
import { SocketIoAdapter } from './service/modules/ws/socket-io.adapter';
import { setupSwagger } from './setup-swagger';
// import { ConfigService } from '@nestjs/config';
import fastifyMutipart from 'fastify-multipart';
import loggerLog from './common/log/logger';
import * as fs from 'fs';
import * as fse from 'fs-extra';
import { deleteFolderRecursive, copyFolderRecursiveSync } from './service/httpOrder/utils';
// import serveStatic from '@fastify/serve-static';
// import fastifyStatic from 'fastify-static';
import serveStatic from 'serve-static';

process.env.ELECTRON_DISABLE_SECURITY_WARNINGS = 'true';

async function electronAppInit() {
  const isDev = !electronApp.isPackaged;

  const targetFolderPath = `${electronApp.getPath('userData')}/HostSqlite`;

  const sqlitePath = `${electronApp.getPath('userData')}/Sqlite`;

  if (fs.existsSync(targetFolderPath)) {
    deleteFolderRecursive(sqlitePath);
    if (fs.existsSync(sqlitePath)) {
      await fse.copySync(sqlitePath, `${electronApp.getPath('userData')}/BackUpSqlite`);

      deleteFolderRecursive(sqlitePath);
    }

    fs.mkdirSync(sqlitePath, { recursive: true });

    // deleteFolderRecursive(sqlitePath);

    copyFolderRecursiveSync(targetFolderPath, sqlitePath);

    deleteFolderRecursive(targetFolderPath);

    console.log('本地同步主机数据库');
  }

  electronApp.on('window-all-closed', () => {
    if (process.platform !== 'darwin') electronApp.quit();
  });

  if (isDev) {
    if (process.platform === 'win32') {
      process.on('message', (data) => {
        if (data === 'graceful-exit') electronApp.quit();
      });
    } else {
      process.on('SIGTERM', () => {
        electronApp.quit();
      });
    }
  }

  await electronApp.whenReady();
}

const SERVER_PORT = 3000;

async function bootstrap() {
  try {
    const isDev = !electronApp.isPackaged;

    await electronAppInit();

    const nestApp = await NestFactory.createMicroservice<MicroserviceOptions>(IpcModule, {
      strategy: new ElectronIpcTransport('IpcTransport'),
    });

    await nestApp.listen();

    const app = await NestFactory.create<NestFastifyApplication>(AppModule, new FastifyAdapter(), {
      bufferLogs: true,
    });

    app.register(fastifyMutipart, {
      addToBody: true,
    });

    app.enableCors({
      credentials: true,
    });

    app.useLogger(app.get(LoggerService));

    // app.register(serveStatic, {
    //   root: join(electronApp.getPath('userData'), '/UploadFile'),
    //   prefix: '/file',
    // });

    // app.register(serveStatic, {
    //   root: `${join(electronApp.getAppPath(), 'dist', 'render')}`,
    //   prefix: '/',
    // });

    app.use('/file', serveStatic(join(electronApp.getPath('userData'), '/UploadFile')));

    // app.register(fastifyStatic, {
    //   root: join(electronApp.getPath('userData'), '/UploadFile'),
    //   prefix: '/file',
    // });

    // app.register(fastifyStatic, { root: pubilcPath, prefix: '/file' });

    // app.useStaticAssets({ root: pubilcPath, prefix: '/file' });

    // app.use('/', serveStatic(join(electronApp.getPath('userData'), '/UploadFile')));

    if (!isDev) {
      app.use('/', serveStatic(join(electronApp.getAppPath(), 'dist', 'render')));
      // app.register(fastifyStatic, {
      //   root: `${join(electronApp.getAppPath(), 'dist', 'render')}`,
      //   prefix: '/',
      // });
      // app.useStaticAssets({
      //   root: `${join(electronApp.getAppPath(), 'dist', 'render')}`,
      //   prefix: '/',
      // });
      // app.register(fastifyStatic, {
      //   root: `${join(electronApp.getAppPath(), 'dist', 'render')}`,
      //   prefix: '/',
      // });
    }

    // app.useStaticAssets({ root: pubilcPath, prefix: '/' });
    // validate
    app.useGlobalPipes(
      new ValidationPipe({
        transform: true,
        whitelist: true,
        forbidNonWhitelisted: true,
        errorHttpStatusCode: HttpStatus.UNPROCESSABLE_ENTITY,
        exceptionFactory: (errors: ValidationError[]) => {
          return new UnprocessableEntityException(
            errors
              .filter((item) => !!item.constraints)
              .flatMap((item) => Object.values(item.constraints))
              .join('; ')
          );
        },
      })
    );
    // execption
    app.useGlobalFilters(new ApiExceptionFilter(app.get(LoggerService)));
    // api interceptor
    app.useGlobalInterceptors(new ApiTransformInterceptor(new Reflector()));
    // websocket
    app.useWebSocketAdapter(new SocketIoAdapter(app));
    // swagger
    setupSwagger(app);
    // start
    await app.listen(SERVER_PORT, '0.0.0.0');
    const serverUrl = await app.getUrl();
    console.log(serverUrl);
    Logger.log(`api服务已经启动,请访问: ${serverUrl}`);
    Logger.log(`API文档已生成,请访问: ${serverUrl}/${process.env.SWAGGER_PATH}/`);
    Logger.log(
      `ws服务已经启动,请访问: ws://${serverUrl
        .replace(`:${SERVER_PORT}`, '')
        .replace(`http://`, '')}:${process.env.WS_PORT || '7002'}${process.env.WS_PATH}`
    );

    // console.log(
    //   `ws服务已经启动,请访问: ws://${serverUrl}:${process.env.WS_PORT || '7002'}${
    //     process.env.WS_PATH
    //   }`
    // );
  } catch (error) {
    // eslint-disable-next-line no-console
    console.log(error);
    // 监听应用程序退出事件，在退出前记录日志
    loggerLog.error('监听应用程序退出事件，在退出前记录日志:' + error);
    electronApp.quit();
  }
}

bootstrap();
